/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.jfonia.view;

import java.awt.Color;
import java.awt.event.MouseEvent;
import org.jfonia.view.panels.ViewPanel;
import java.awt.Graphics;
import java.awt.event.MouseListener;
import java.util.Collection;
import org.jfonia.connect5.basics.BasicValueNode;
import org.jfonia.connect5.basics.MutableValueNode;
import org.jfonia.connect5.intervals.BasicDoubleInterval;
import org.jfonia.connect5.intervals.Interval;
import org.jfonia.connect5.relations.Equal;
import org.jfonia.constants.ViewConstants;
import org.jfonia.model.IListObserver;
import org.jfonia.model.Sequence;
import org.jfonia.model.Staff;
import org.jfonia.model.elements.Chord;
import org.jfonia.model.elements.Lyric;
import org.jfonia.view.elements.IElement;
import org.jfonia.view.panels.BasicNodePanel;
import org.jfonia.view.panels.ViewLayerPanel;

/**
 *
 * @author Rik Bauwens
 */
public class StaffView implements IListObserver<Sequence>
{
        private StaffCollectionView staffCollectionView;
        private StaffBoxPanel boxPanel;
        private ViewPanel viewPanel;
        private ViewLayerPanel viewLayerPanel;

        private Staff staff;
        //private LinkedDoubleIntervalList xNodes;
        private RelationBuilder relationBuilder;
        private MutableValueNode<Double> yNode;
        private MutableValueNode<Double> heightNode;
        private BasicDoubleInterval yOrientation;
        private SequenceView sequenceView;

        private MutableValueNode<Boolean> staffSelectionNode;

        public StaffView(ViewPanel viewPanel, ViewLayerPanel viewLayerPanel,
                         Staff staff, RelationBuilder relationBuilder,
                         StaffCollectionView staffCollectionView,
                         MutableValueNode<Double> yNode,
                         MutableValueNode<Double> heightNode)
        {
                this.staffCollectionView = staffCollectionView;
                //Box panel
                this.boxPanel = new StaffBoxPanel(relationBuilder.getPreStaffInterval().getBeginNode(),
                                                  yNode, relationBuilder.getPreStaffInterval().getDifferenceNode(),
                                                  heightNode);
                viewPanel.add(boxPanel);

                this.viewPanel = viewPanel;
                this.viewLayerPanel = viewLayerPanel;
                
                this.relationBuilder = relationBuilder;

                this.yNode = new BasicValueNode<Double>(0.0);
                new Equal<Double>(yNode, this.yNode);
                this.heightNode = new BasicValueNode<Double>(0.0);
                new Equal<Double>(heightNode, this.heightNode);
                yOrientation = new BasicDoubleInterval();
                new Equal<Double>(this.yNode, yOrientation.getBeginNode());
                new Equal<Double>(this.heightNode, yOrientation.getDifferenceNode());

                staffSelectionNode = new BasicValueNode<Boolean>(false);
                setStaff(staff);
        }

        public boolean hasFocus()
        {
                return relationBuilder.hasElementFocus();
        }

        public Interval<Double> getYOrientation()
        {
                return yOrientation;
        }

        public MutableValueNode<Boolean> getStaffCollectionSelectionNode()
        {
                return staffCollectionView.getStaffCollectionSelectionNode();
        }

        public MutableValueNode<Boolean> getStaffSelectionNode()
        {
                return staffSelectionNode;
        }

        public StaffView staffViewAbove()
        {
                return staffCollectionView.staffViewAbove(this);
        }

        public StaffView staffViewBelow()
        {
                return staffCollectionView.staffViewBelow(this);
        }

        public Staff getStaff()
        {
                return staff;
        }

        public IElement getElement(int tick, int index)
        {
                return sequenceView.getElement(tick, index);
        }

        private void setStaff(Staff staff)
        {
                this.staff = staff;                
                staff.addObserver(this);
                Collection<Sequence> collection = staff.getSequences();
                for(Sequence seq : collection)
                        itemAdded(seq);
        }

        public void paintComponent(Graphics g)
        {

        }

        //Sequence added to the staff, it will only be added to a view if:
        //  * There is no view yet, the view can either be of a single sequence (chord/lyrics),
        //    or a multisequence (tone, clef, keysignature, timesignature)
        //  * There is view already, but it's mulisequenceview
        public void itemAdded(Sequence item)
        {
                if(sequenceView == null && (item.getTemplateClass().equals(Chord.class)
                   || item.getTemplateClass().equals(Lyric.class)))
                {
                        sequenceView = new SequenceView(viewPanel, viewLayerPanel,
                                this, false, relationBuilder, yNode, heightNode);
                }
                else
                {
                        if(sequenceView == null)
                                sequenceView = new SequenceView(viewPanel, viewLayerPanel,
                                        this, true, relationBuilder, yNode, heightNode);
                }
                sequenceView.addSequence(item);
        }

        //Sequence removed from the staff
        public void itemRemoved(Sequence item)
        {
                if(sequenceView != null)
                {
                        sequenceView.removeSequence(item);
                }
        }

        private class StaffBoxPanel extends BasicNodePanel implements MouseListener
        {
                private boolean draw;
                private Color background;

                public StaffBoxPanel(MutableValueNode<Double> xNode, MutableValueNode<Double> yNode,
                                     MutableValueNode<Double> widthNode, MutableValueNode<Double> heightNode)
                {
                        super(xNode, yNode, widthNode, heightNode);
                        drawBox(false);
                        addMouseListener(this);
                        setBackground(ViewConstants.MAIN_BACKGROUND_COLOR);
                        setSelected(false);
                }

                @Override
                protected void paintComponent(Graphics g)
                {
                        super.paintComponent(g);
                        if(!draw && !isSelected())
                                return;
                        g.setColor(background);
                        g.fillRoundRect((int) ViewConstants.STAFF_BOX_LEFT_MARGIN, 0,
                                (int) ViewConstants.STAFF_BOX_WIDTH, heightNode.getValue().intValue(),
                                ViewConstants.ROUNDRECT_ARC_WIDTH, ViewConstants.ROUNDRECT_ARC_HEIGHT);
                }

                private boolean isSelected()
                {
                        return background == ViewConstants.STAFF_BOX_SELECTED_COLOR;
                }

                private void setSelected(boolean selected)
                {
                        if(selected)
                                background = ViewConstants.STAFF_BOX_SELECTED_COLOR;
                        else
                                background = ViewConstants.STAFF_BOX_COLOR;
                        repaint();
                }

                private void drawBox(boolean draw)
                {
                        this.draw = draw;
                        repaint();
                }

                public void mouseClicked(MouseEvent e) {}

                public void mouseEntered(MouseEvent e)
                {
                        drawBox(true);
                }

                public void mouseExited(MouseEvent e)
                {
                        drawBox(false);
                }

                public void mousePressed(MouseEvent e) {}
                public void mouseReleased(MouseEvent e) {}
        }
}
